#ifndef __MY_FORMAT_H__
#define __MY_FORMAT_H__
#include "Lever.hpp"
#include "Message.hpp"
#include <ctime>
#include <sstream>
#include <vector>
#include <cassert>
using namespace std;
// 日志格式化输出类

// 子项包括:时间、等级、文件名、行号、线程ID、日志器名称、消息主体、其他消息、制表符、换行
namespace Format
{
    // FormatItem类主要负责⽇志消息⼦项数据的获取及格式化
    class FormatItem
    {
    public:
        using ptr = shared_ptr<FormatItem>;
        virtual void format(ostream &out, Message::LogMsg &msg) = 0;
    };
    class OtherFormatItem : public FormatItem
    {
    public:
        OtherFormatItem(const string &str = "") : other(str) {}
        void format(ostream &out, Message::LogMsg &msg)
        {
            out << other;
        }

    private:
        string other;
    };
    class NLineFormatItem : public FormatItem
    {
    public:
        void format(ostream &out, Message::LogMsg &msg)
        {
            out << "\n";
        }
    };
    class TabFormatItem : public FormatItem
    {
    public:
        void format(ostream &out, Message::LogMsg &msg)
        {
            out << "\t";
        }
    };
    class MsgFormatItem : public FormatItem
    {
    public:
        void format(ostream &out, Message::LogMsg &msg)
        {
            out << msg._payload;
        }
    };
    class LoggerFormatItem : public FormatItem
    {
    public:
        void format(ostream &out, Message::LogMsg &msg)
        {
            out << msg._logger;
        }
    };
    class ThreadFormatItem : public FormatItem
    {
    public:
        void format(ostream &out, Message::LogMsg &msg)
        {
            out << msg._tid;
        }
    };
    class LineFormatItem : public FormatItem
    {
    public:
        void format(ostream &out, Message::LogMsg &msg)
        {
            out << msg._line;
        }
    };
    class FileFormatItem : public FormatItem
    {
    public:
        void format(ostream &out, Message::LogMsg &msg)
        {
            out << msg._filename;
        }
    };
    class LevelFormatItem : public FormatItem
    {
    public:
        void format(ostream &out, Message::LogMsg &msg)
        {
            out << Level::LogLevel::toString(msg._level);
        }
    };
    class TimeFormatItem : public FormatItem
    {
    public:
        TimeFormatItem(const string &fmt = "%H:%M:%S") : _format(fmt) {}
        void format(ostream &out, Message::LogMsg &msg)
        {
            struct tm t;
            localtime_r(&msg._ctime, &t);
            char buffer[32] = {0};
            strftime(buffer, 31, _format.c_str(), &t);
            out << buffer;
        }

    private:
        string _format;
    };

    // 格式化的过程其实就是按次序从Msg中取出需要的数据进⾏字符串的连接的过程。
    class Formatter // 日志格式器（负者对解析字符串进行按序格式化）
    {
    public:
        using ptr = shared_ptr<Formatter>;
        Formatter(const string &pattern = "[%d{%H:%M:%S}][%f:%l][%t][%c][%p]%T%m%n") : _pattern(pattern)
        {
            // 在格式化前，必须解析字符串成功
            assert(prasePattern());
        }
        // 对msg中的内容进行格式化
        string format(Message::LogMsg &msg)
        {
            stringstream ss;
            format(ss, msg);
            return ss.str(); // 返回组织好且格式化后的信息
        }
        void format(ostream &out, Message::LogMsg &msg) // 根据按序保存的⼦格式化对象，组织数据
        {
            for (auto &item : _items)
                item->format(out, msg);
        }

    private:
        // 对格式化规则字符串进行解析
        // abc[%d{%H:%M:%S}][%f:%l][%t][%c][%p]%T%m%n
        bool prasePattern()
        {
            vector<pair<string, string>> ft; // 保存解析后的字符串
            int pos = 0;
            string key, val;
            while (pos < _pattern.size()) // 逐个遍历字符
            {
                if (_pattern[pos] != '%')
                {
                    val.push_back(_pattern[pos++]);
                    continue;
                }
                if (pos + 1 < _pattern.size() && _pattern[pos + 1] == '%')
                {
                    val.push_back('%');
                    pos += 2;
                    continue;
                }
                // 如果val的值不为空,说明存有原始字符串
                if (!val.empty())
                {
                    ft.push_back(make_pair("", val));
                    val.clear();
                }
                // 走到这个位置说明当前位置为%,并且下一个字符不是%
                pos += 1;
                if (pos == _pattern.size())
                {
                    cout << "%之后，没有对应的格式化字符!\n";
                    return false;
                }
                key = _pattern[pos];
                pos += 1;
                if (pos < _pattern.size() && _pattern[pos] == '{')
                {
                    pos += 1; // pos指向花括号下⼀个字符
                    while (pos < _pattern.size() && _pattern[pos] != '}')
                    {
                        val += _pattern[pos];
                        pos++;
                    }
                    if (pos == _pattern.size())
                    {
                        cout << "子字符串解析失败，没有对应的}\n";
                        return false;
                    }
                    pos += 1; // 因为此时pos处在}为位置，需要走到下一次要处理的新位置
                }
                ft.push_back(make_pair(key, val));
                key.clear();
                val.clear();
            }
            for (auto &item : ft)
                _items.push_back(createItem(item.first, item.second));
            return true;
        }
        /*
                  %d ⽇期
                  %T 缩进
                  %t 线程id
                  %p ⽇志级别
                  %c ⽇志器名称
                  %f ⽂件名
                  %l ⾏号
                  %m ⽇志消息
                  %n 换⾏
         */
        // 根据字符串解析的Key返回相应子格式化对象
        FormatItem::ptr createItem(const string &key, const string &value)
        {
            if (key == "d")
                return make_shared<TimeFormatItem>(value);
            if (key == "t")
                return make_shared<ThreadFormatItem>();
            if (key == "p")
                return make_shared<LevelFormatItem>();
            if (key == "c")
                return make_shared<LoggerFormatItem>();
            if (key == "f")
                return make_shared<FileFormatItem>();
            if (key == "l")
                return make_shared<LineFormatItem>();
            if (key == "m")
                return make_shared<MsgFormatItem>();
            if (key == "n")
                return make_shared<NLineFormatItem>();
            if (key == "T")
                return make_shared<TabFormatItem>();
            if (key.empty())
                return make_shared<OtherFormatItem>(value);
            cout << "没有匹配的格式化字符" << key << endl;
            abort();
            return FormatItem::ptr();
        }

    private:
        string _pattern;
        vector<FormatItem::ptr> _items; // ⽤于按序保存格式化字符串对应的⼦格式化对象。
    };
}
#endif